package com.oneraku.service.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.oneraku.service.dao.WishOrderMapper;
import com.oneraku.service.dao.WorkOrderCommentMapper;
import com.oneraku.service.domain.UserInfo;
import com.oneraku.service.dao.UserInfoMapper;
import com.oneraku.service.domain.VerifyCodeRecord;
import com.oneraku.service.domain.WorkOrderComment;
import com.oneraku.service.dto.MargePassword;
import com.oneraku.service.dto.VerifyCode;
import com.oneraku.service.exceptions.InfoException;
import com.oneraku.service.listener.MailEvent;
import com.oneraku.service.listener.SmsEvent;
import com.oneraku.service.service.IUserInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.oneraku.service.service.IVerifyCodeRecordService;
import com.oneraku.service.utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Random;
import java.util.regex.Pattern;

/**
 * <p>
 * 用户信息 服务实现类
 * </p>
 *
 * @author renhui <337375464@qq.com>
 * @since 2020-02-25
 */
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements IUserInfoService {
    private ApplicationContext publisher;
    private IVerifyCodeRecordService verifyCodeRecordService;
    private WishOrderMapper wishOrderMapper;
    private WorkOrderCommentMapper commentMapper;
    @Autowired
    public UserInfoServiceImpl(ApplicationContext publisher,IVerifyCodeRecordService verifyCodeRecordService,WishOrderMapper wishOrderMapper,WorkOrderCommentMapper commentMapper) {
        this.publisher = publisher;
        this.verifyCodeRecordService = verifyCodeRecordService;
        this.wishOrderMapper = wishOrderMapper;
        this.commentMapper = commentMapper;
    }
    @Override
    public R login(UserInfo userInfo) {
        if(StringUtils.isEmpty(userInfo.getUsername())){
            throw new InfoException("登录密码不能为空！");
        }
        if(StringUtils.isEmpty(userInfo.getPassword())){
            throw new InfoException("登录密码不能为空！");
        }
        UserInfo localUserInfo = getOne(Wrappers.<UserInfo>lambdaQuery().eq(UserInfo::getUsername,userInfo.getUsername()));
        if(null == localUserInfo){
            throw new InfoException("未找到相关的用户！");
        }
        // 密码使用md5加密
        if(!Bcrypt.checkpw(userInfo.getPassword(),localUserInfo.getPassword())){
            throw new InfoException("用户或密码不正确！");
        }
        String token = TokenUtils.getToken(localUserInfo.getId());
        getBaseMapper().update(
                null,
                Wrappers.<UserInfo>lambdaUpdate().set(UserInfo::getToken, token).set(UserInfo::getTokenExpire, System.currentTimeMillis() + Const.expire).eq(UserInfo::getId, localUserInfo.getId())
        );
        AuthBean authBean = new AuthBean();
        authBean.setToken(token);
        authBean.setId(localUserInfo.getId());
        authBean.setName(localUserInfo.getName());
        authBean.setUsername(localUserInfo.getUsername());
        authBean.setMobile(localUserInfo.getMobile());
        authBean.setMail(localUserInfo.getMail());
        return R.ok(authBean);
    }
    @Override
    public R loginAdmin(UserInfo userInfo) {


        return null;
    }
    @Override
    public R register(UserInfo userInfo) {
        if(StringUtils.isEmpty(userInfo.getUsername())){
            throw new InfoException("用户名不能为空");
        }
        if(StringUtils.isEmpty(userInfo.getPassword())){
            throw new InfoException("用户密码不能为空");
        }
        boolean isMobile = Pattern.compile(Const.mobilePattern).matcher(userInfo.getUsername()).matches();
        if(!isMobile){
            throw new InfoException("账号必须是手机号");
        }
        UserInfo localUserInfo = getOne(Wrappers.<UserInfo>lambdaQuery().eq(UserInfo::getUsername,userInfo.getUsername()));
        if(null != localUserInfo){
            throw new InfoException("用户名已存在，不能重复注册！");
        }
        UserInfo newUser = new UserInfo();
        newUser.setName(userInfo.getUsername());
        newUser.setUsername(userInfo.getUsername());
        newUser.setPassword(Bcrypt.hashpw(userInfo.getPassword(),Bcrypt.gensalt()));
        newUser.setMobile(userInfo.getUsername());
        if(StringUtils.isEmpty(newUser.getAvatar())){
            newUser.setAvatar(String.format("https://oneraku-resource.oss-cn-shanghai.aliyuncs.com/avatar/%s.jpg",new Random().nextInt(9)));
        }
        save(newUser);
        return R.ok(newUser.getId());
    }
    @Override
    public R edit(UserInfo userInfo) {
        AuthBean authBean = RequestUserUtils.getUser();
        String id = authBean.getId();
        UserInfo updateUser = new UserInfo();
        updateUser.setId(id);
        updateUser.setAvatar(userInfo.getAvatar());
        updateUser.setName(userInfo.getName());
        updateUser.setBirthday(userInfo.getBirthday());
        updateUser.setSex(userInfo.getSex());
        if(!StringUtils.isEmpty(userInfo.getNotice())){
            updateUser.setNotice(userInfo.getNotice());
        }
        return R.ok(updateById(updateUser));
    }
    @Override
    public R margePassword(MargePassword margePassword) {
        if(StringUtils.isEmpty(margePassword.getNumber())){
            throw new InfoException("邮箱或邮箱不能为空");
        }
        if(StringUtils.isEmpty(margePassword.getPassword())){
            throw new InfoException("要修改的密码不能为空");
        }
        boolean isMobile = Pattern.compile(Const.mobilePattern).matcher(margePassword.getNumber()).matches();
        boolean isMail = Pattern.compile(Const.mailPattern).matcher(margePassword.getNumber()).matches();
        if(!isMobile && !isMail){
            throw new InfoException("手机号或邮箱不正确!");
        }
        AuthBean authBean = RequestUserUtils.getUser();
        List<VerifyCodeRecord> recordList;
        if(isMobile){
            // 通过手机号修改
            recordList = verifyCodeRecordService.list(Wrappers.<VerifyCodeRecord>lambdaQuery()
                    .eq(VerifyCodeRecord::getUid,authBean.getId())
                    .eq(VerifyCodeRecord::getNumber,margePassword.getNumber())
                    .eq(VerifyCodeRecord::getType,Const.VerifyCodeMobilePassword)
                    .gt(VerifyCodeRecord::getExpire,System.currentTimeMillis()));
        } else if(isMail){
            // 通过邮箱修改
            recordList = verifyCodeRecordService.list(Wrappers.<VerifyCodeRecord>lambdaQuery()
                    .eq(VerifyCodeRecord::getUid,authBean.getId())
                    .eq(VerifyCodeRecord::getNumber,margePassword.getNumber())
                    .eq(VerifyCodeRecord::getType,Const.VerifyCodeMailPassword)
                    .gt(VerifyCodeRecord::getExpire,System.currentTimeMillis()));
        } else {
            throw new InfoException("邮箱或手机号不正确");
        }
        if(recordList.size() == 0){
            throw new InfoException("验证码已失效");
        }
        VerifyCodeRecord record = recordList.get(0);
        if(!margePassword.getVerifyCode().equals(record.getCode())){
            throw new InfoException("验证码不正确");
        }
        boolean update = update(Wrappers.<UserInfo>lambdaUpdate().set(UserInfo::getPassword,Bcrypt.hashpw(margePassword.getPassword(),Bcrypt.gensalt())).eq(UserInfo::getId,authBean.getId()));
        return R.ok(update);
    }
    @Override
    public R verifyCode(VerifyCode verifyCode) {
        Const.checkVerifyCodeValid(verifyCode.getType());
        String verifyCodeStr = String.valueOf(new Random().nextInt(899999) + 100000);
        if(Const.VerifyCodeMobileChange.equals(verifyCode.getType()) || Const.VerifyCodeMobilePassword.equals(verifyCode.getType())){
            if(StringUtils.isEmpty(verifyCode.getNumber())){
                throw new InfoException("手机号不能为空!");
            }
            boolean isMobile = Pattern.compile(Const.mobilePattern).matcher(verifyCode.getNumber()).matches();
            if(!isMobile){
                throw new InfoException("手机号不正确!");
            }
            SmsEvent smsEvent = new SmsEvent(this, verifyCode.getNumber(), verifyCodeStr,verifyCode.getType());
            publisher.publishEvent(smsEvent);
        } else {
            if(StringUtils.isEmpty(verifyCode.getNumber())){
                throw new InfoException("邮箱不能为空!");
            }
            boolean isMail = Pattern.compile(Const.mailPattern).matcher(verifyCode.getNumber()).matches();
            if(!isMail){
                throw new InfoException("邮箱不正确!");
            }
            MailEvent smsEvent = new MailEvent(this, verifyCode.getNumber(), verifyCodeStr,verifyCode.getType());
            publisher.publishEvent(smsEvent);
        }
        return R.ok("success");
    }
    @Override
    public R changeNumber(MargePassword margePassword) {
        if(StringUtils.isEmpty(margePassword.getNumber())){
            throw new InfoException("新的手机号或邮箱不能为空");
        }
        if(StringUtils.isEmpty(margePassword.getVerifyCode())){
            throw new InfoException("验证码不能为空！");
        }
        if(StringUtils.isEmpty(margePassword.getPassword())){
            throw new InfoException("登录密码不能为空！");
        }
        boolean isMobile = Pattern.compile(Const.mobilePattern).matcher(margePassword.getNumber()).matches();
        boolean isMail = Pattern.compile(Const.mailPattern).matcher(margePassword.getNumber()).matches();
        if(!isMobile && !isMail){
            throw new InfoException("手机号或邮箱不正确!");
        }
        AuthBean authBean = RequestUserUtils.getUser();
        UserInfo userInfo = getById(authBean.getId());
        if(!Bcrypt.checkpw(margePassword.getPassword(),userInfo.getPassword())){
            throw new InfoException("用户或密码不正确！");
        }
        List<VerifyCodeRecord> recordList;
        if(isMobile){
            // 通过手机号修改
            recordList = verifyCodeRecordService.list(Wrappers.<VerifyCodeRecord>lambdaQuery()
                    .eq(VerifyCodeRecord::getUid,authBean.getId())
                    .eq(VerifyCodeRecord::getNumber,margePassword.getNumber())
                    .eq(VerifyCodeRecord::getType,Const.VerifyCodeMobileChange)
                    .gt(VerifyCodeRecord::getExpire,System.currentTimeMillis()));
        } else if(isMail){
            // 通过邮箱修改
            recordList = verifyCodeRecordService.list(Wrappers.<VerifyCodeRecord>lambdaQuery()
                    .eq(VerifyCodeRecord::getUid,authBean.getId())
                    .eq(VerifyCodeRecord::getNumber,margePassword.getNumber())
                    .eq(VerifyCodeRecord::getType,Const.VerifyCodeMailChange)
                    .gt(VerifyCodeRecord::getExpire,System.currentTimeMillis()));
        } else {
            throw new InfoException("邮箱或手机号不正确");
        }
        if(recordList.size() == 0){
            throw new InfoException("验证码已失效");
        }
        VerifyCodeRecord record = recordList.get(0);
        if(!margePassword.getVerifyCode().equals(record.getCode())){
            throw new InfoException("验证码不正确");
        }
        boolean update = false;
        if(isMobile){
            update = update(Wrappers.<UserInfo>lambdaUpdate().set(UserInfo::getMobile,margePassword.getNumber()).eq(UserInfo::getId,authBean.getId()));
        } else if(isMail){
            update = update(Wrappers.<UserInfo>lambdaUpdate().set(UserInfo::getMail,margePassword.getNumber()).eq(UserInfo::getId,authBean.getId()));
        } else {
            throw new InfoException("邮箱或手机号不正确");
        }
        return R.ok(update);
    }
    @Override
    public R msg() {
        AuthBean authBean = RequestUserUtils.getUser();
        return R.ok(commentMapper.selectCount(Wrappers.<WorkOrderComment>lambdaQuery().eq(WorkOrderComment::getUid,authBean.getId()).eq(WorkOrderComment::getType,"sys").eq(WorkOrderComment::getRead,false)));
    }
    @Override
    public R info() {
        AuthBean authBean = RequestUserUtils.getUser();
        UserInfo userInfo = getById(authBean.getId());
        userInfo.setPassword(null);
        userInfo.setToken(null);
        userInfo.setTokenExpire(null);
        return R.ok(userInfo);
    }

    @Override
    public R unRegister() {
        AuthBean authBean = RequestUserUtils.getUser();
        removeById(authBean.getId());
        return R.ok("success");
    }
}
